/**
 * Class:				WordDetectionActivity.java
 * 
 * Project:				Bio-inspired car commander
 * 
 * Subproject:			Word Detector
 * 
 * Date: 				Mai - Juillet 2011
 * 
 * Auteurs:				Bruno Da Silva
 * 						Thomas Jordan
 * 
 * Description:
 * Gère l'interface graphique d'entrainement de de reconnaissance. Permet de 
 * lancer l'enregistrement du son, l'extraction des MFCC's, le training du réseau
 * de neurones et la détection de sons.
 * 
 */
package ch.sda.bioinspiredcarcommander;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import mfccExtraction.AudioRecordWrapper;
import mfccExtraction.Bkprop;
import mfccExtraction.MfccMaker;
import mfccExtraction.RawAudioPlayback;
import android.app.Activity;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import ch.sda.bioinspiredcarcommander.words.WordsManager;


public class WordDetectionActivity extends Activity {

	private static final int REC_SECONDES = 2;

	// File Locations
	final String AUDIO_FILE = "/sdcard/SDA/recordoutput.raw";
	final String MFCC_FILE_L = "/sdcard/SDA/learningBase.txt";
	final String MFCC_FILE_P ="/sdcard/SDA/currentWord.txt";
	final String CONFIG_FILE = BioInspiredCarCommander.CONFIG_FILE;

	// Audio Settings
	final int AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;
	final int AUDIO_STREAM = AudioManager.STREAM_MUSIC;
	final int SAMPLE_RATE = 8000;
	final int CHANNELS_IN = AudioFormat.CHANNEL_IN_MONO;
	final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
	final int PLAYBACK_MODE = AudioTrack.MODE_STREAM;
	final int CHANNELS_OUT = AudioFormat.CHANNEL_CONFIGURATION_MONO;
	AudioRecordWrapper recorderWrapper;
	private Boolean trainingMode;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.word_detection);
		trainingMode = this.getIntent().getBooleanExtra("training", false);

		recorderWrapper = new AudioRecordWrapper(AUDIO_FILE, AUDIO_SOURCE, SAMPLE_RATE, 
				CHANNELS_IN, AUDIO_FORMAT);

		setTrainingInterface();

		if (trainingMode) {
			updateTrainingList();
			setTrainingButtonAction();
		}
		setRecButtonAction();


	}
	private String getResult() {

		Log.v("LOL","End of recording... Start MFCC Extraction");

		MfccMaker Mfcc = new MfccMaker(CONFIG_FILE, AUDIO_FILE, MFCC_FILE_L, MFCC_FILE_P); 

		if(trainingMode)
		{

			final Context ctx = this;
			final Spinner spin =(Spinner)findViewById(R.id.choiceWordList);
			String word = WordsManager.sharedManager(ctx).getWords().get(spin.getSelectedItemPosition());
			Mfcc.produceFeatures(word, BioInspiredCarCommander.wm.getWords().size());
		}
		else
		{
			Mfcc.produceFeatures(null, BioInspiredCarCommander.wm.getWords().size());

			Log.v("LOL","Extraction done");

			Log.v("LOL", Mfcc.getLastMFCC().getLast());

			//Gives the MFCC to the MLP
			try {

				String wordDetected = BioInspiredCarCommander.wordDetector.evaluateMFCCs();

				new File(MFCC_FILE_P).delete();
				new File(AUDIO_FILE).delete();

				return wordDetected;
			} catch (FileNotFoundException e) {	e.printStackTrace();}
		}
		
		//pLAY THE RECORDER SOUND TO THE USER TO CHECK QUALITY
		RawAudioPlayback rap = new RawAudioPlayback(AUDIO_FILE, AUDIO_STREAM, SAMPLE_RATE, CHANNELS_OUT, AUDIO_FORMAT, PLAYBACK_MODE );
		try {
			rap.play();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "Network Training :)";
	}

	private void updateTrainingList() {
		HashMap<String, Integer> nbTraining = BioInspiredCarCommander.wordDetector.getNbLearnSampleForWords();
		List<String> l = new ArrayList<String>();

		for (String w : WordsManager.sharedManager(this).getWords()) {
			l.add(w + " (" + nbTraining.get(w) + ")");
		}
		Spinner spin = (Spinner) findViewById(R.id.choiceWordList);

		ArrayAdapter<String> adapter = new ArrayAdapter<String>(spin.getContext(),android.R.layout.simple_spinner_item,l);
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spin.setAdapter(adapter);
	}

	private void setTrainingInterface() {
		Spinner spinner = (Spinner)findViewById(R.id.choiceWordList);
		TextView wordResult = (TextView)findViewById(R.id.wordResult);
		FrameLayout trainingFrame = (FrameLayout)findViewById(R.id.trainingFrame);
		FrameLayout recFrame = (FrameLayout)findViewById(R.id.recFrame);

		recFrame.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, (trainingMode?1:0)));

		spinner.setVisibility(trainingMode?View.VISIBLE:View.INVISIBLE);
		trainingFrame.setVisibility(spinner.getVisibility());

		wordResult.setVisibility(trainingMode?View.INVISIBLE:View.VISIBLE);

		TextView tvTitle = (TextView)findViewById(R.id.tvTitle);
		tvTitle.setText(trainingMode?"Network Training":"Word Detector");
	}

	private void setRecButtonAction() {

		final ImageButton recButton = (ImageButton)findViewById(R.id.recButton);
		final TextView tvWordResult = (TextView) findViewById(R.id.wordResult);
		final Context ctx = this;

		recButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {

				final int itemSelected = ((Spinner)findViewById(R.id.choiceWordList)).getSelectedItemPosition();

				new Thread() {
					@Override
					public void run() {

						final ImageView[] images = new ImageView[]{(ImageView) findViewById(R.id.lightImage1),(ImageView) findViewById(R.id.lightImage2),(ImageView) findViewById(R.id.lightImage3)};
						final FrameLayout imgsLayout = (FrameLayout) findViewById(R.id.lightsFrame);
						final ProgressBar pg = (ProgressBar) findViewById(R.id.progressBar);
						final Spinner spin =(Spinner)findViewById(R.id.choiceWordList);
						final ImageButton trainingButton = (ImageButton)findViewById(R.id.trainingButton);

						runOnMainThread(new Runnable() {

							@Override
							public void run() {


								spin.setVisibility(View.INVISIBLE);
								tvWordResult.setVisibility(View.VISIBLE);
								String word = "a word";
								if (trainingMode)
									word = WordsManager.sharedManager(ctx).getWords().get(spin.getSelectedItemPosition());
								tvWordResult.setText("Say " + (trainingMode?"'"+ word +"'":"a word"));
								recButton.setEnabled(false);
								trainingButton.setEnabled(false);
								Log.v("blop","Start recording");

							}
						});

						new Thread() {
							@Override
							public void run() {
								recorderWrapper.record();
							};
						}.start();

						int cpt = 0;
						int interval = (REC_SECONDES*1000)/3;
						while (cpt<3) {
							try {
								final ImageView iv = images[cpt++];
								runOnMainThread(new Runnable() {

									@Override
									public void run() {
										iv.setImageResource(R.drawable.green_light);
									}
								});
								sleep(interval);

							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}

						runOnMainThread(new Runnable() {

							@Override
							public void run() {
								imgsLayout.setVisibility(View.INVISIBLE);
								pg.setVisibility(View.VISIBLE);
								String text = trainingMode ? "Process..." : "Searching...";
								tvWordResult.setText(text);
							}
						});

						String wr = null;
						wr = getResult();
						final String wordResult = wr;

						runOnMainThread(new Runnable() {

							@Override
							public void run() {
								if (trainingMode) {
									updateTrainingList();
									spin.setVisibility(View.VISIBLE);
									selectCurrentWord(spin);
									tvWordResult.setVisibility(View.INVISIBLE);
									spin.setSelection(itemSelected);
								}
								else {
									tvWordResult.setText(wordResult);
									tvWordResult.setVisibility(View.VISIBLE);
								}

								for(final ImageView iv : images) {
									iv.setImageResource(R.drawable.gray_light);
								}
								imgsLayout.setVisibility(View.VISIBLE);
								pg.setVisibility(View.INVISIBLE);
								recButton.setEnabled(true);
								trainingButton.setEnabled(true);
							}

							private void selectCurrentWord(Spinner spin) {


							}
						});
					}

				}.start();
			}
		});

	}

	private void setTrainingButtonAction() {
		final ImageButton trainingButton = (ImageButton)findViewById(R.id.trainingButton);

		trainingButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				new Thread() {
					@Override
					public void run() {
						final Spinner spin = (Spinner)findViewById(R.id.choiceWordList);
						final ProgressBar pg = (ProgressBar)findViewById(R.id.progressBar);
						final ImageButton recButton = (ImageButton)findViewById(R.id.recButton);
						final FrameLayout imgsLayout = (FrameLayout) findViewById(R.id.lightsFrame);
						final TextView tv = (TextView)findViewById(R.id.wordResult);

						runOnMainThread(new Runnable() {

							@Override
							public void run() {
								spin.setVisibility(View.INVISIBLE);
								pg.setVisibility(View.VISIBLE);
								trainingButton.setEnabled(false);
								recButton.setEnabled(false);
								imgsLayout.setVisibility(View.INVISIBLE);
								tv.setVisibility(View.VISIBLE);
								tv.setText("Training");
							}
						});


						BioInspiredCarCommander.wordDetector.generateDynamicDataset();

						BioInspiredCarCommander.wordDetector.setNetwork(new Bkprop(BioInspiredCarCommander.wm.getWords().size(), BioInspiredCarCommander.dynamicLearningDatasetPath, BioInspiredCarCommander.MFCC_FILE_P));

						// TODO Add set training call
						BioInspiredCarCommander.wordDetector.trainMLP(BioInspiredCarCommander.wordDetector.getNetwork());

						BioInspiredCarCommander.wordDetector.getNetwork().saveNetwork(BioInspiredCarCommander.ANN_FILE);

						runOnMainThread(new Runnable() {

							@Override
							public void run() {
								spin.setVisibility(View.VISIBLE);
								pg.setVisibility(View.INVISIBLE);
								trainingButton.setEnabled(true);
								recButton.setEnabled(true);
								imgsLayout.setVisibility(View.VISIBLE);
								tv.setVisibility(View.INVISIBLE);
							}
						});


					}
				}.start();
			}
		});
	}

	private void runOnMainThread(Runnable action) {
		this.runOnUiThread(action);
	}
}

